namespace cframework_xlua {
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine.EventSystems;
using Newtonsoft.Json;
using System.Linq;

public static class CommonUtil
{
    public static long GetTimeStamp(bool isSecond = true)
    {
        System.TimeSpan ts = System.DateTime.UtcNow - new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
        long ret;
        if (isSecond)
            ret = System.Convert.ToInt64(ts.TotalSeconds);
        else
            ret = System.Convert.ToInt64(ts.TotalMilliseconds);
        return ret;
    }

    public static string md5(string input)
    {
        // step 1, calculate MD5 hash from input
        MD5 md5 = MD5.Create();
        byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
        byte[] hash = md5.ComputeHash(inputBytes);

        // step 2, convert byte array to hex string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
    }

    public static string md5(byte[] inputBytes)
    {
        // step 1, calculate MD5 hash from input
        MD5 md5 = MD5.Create();
        byte[] hash = md5.ComputeHash(inputBytes);

        // step 2, convert byte array to hex string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
    }

    public static string cachePath
    {
        get
        {
//            if(Application.isEditor)
//            {
//                return Application.persistentDataPath;
//            }
//            else if(Application.platform == RuntimePlatform.Android)
//            {
//                #if UNITY_ANDROID && !UNITY_EDITOR
//                //return ChatPluginAndroid.Instance.GetWritablePath() + "/files";
//                #endif
//            }
//            return Application.temporaryCachePath;

            if (Application.platform == RuntimePlatform.IPhonePlayer)
            {
                return Application.temporaryCachePath;
            }

            return Application.persistentDataPath;
        }
    }

    public static string addSuffixToFileName(string path, string suffix)
    {
        string dir = Path.GetDirectoryName(path);
        string fileName = Path.GetFileNameWithoutExtension(path);
        string extName = Path.GetExtension(path);

        string temp = fileName + suffix + extName;
        if (!string.IsNullOrEmpty(dir))
        {
            temp = dir + "/" + temp;
        }

        return temp;
    }

    public static string fileToString(string filePath)
    {
        if(!File.Exists(filePath))
        {
            return null;
        }

        return File.ReadAllText(filePath);
    }

    public static bool bytesToFile(string filePath, byte[] bytes)
    {
#if !WEBPLAYER
        try
        {
        #if UNITY_EDITOR_WIN
            if(File.Exists(filePath))
            {
                new FileInfo(@filePath).Attributes = FileAttributes.Normal; 
            }
        #endif 
            File.WriteAllBytes(filePath, bytes);
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
            CommonUtil.Delete(filePath);
            return false;
        }
#endif
        return true;
    }

    public static string[] GetFiles(string dir, string findStr, SearchOption option)
    {
        try
        {
            string[] files = Directory.GetFiles(dir, findStr, option);
            return files;
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
        }
        return null;
    }

    public static bool Exists(string path)
    {
        try
        {
            return File.Exists(path) || Directory.Exists(path);
        }
        catch(System.IO.DirectoryNotFoundException e)
        {
            return false;
        }
    }

    public static bool Copy(string inFilePath, string outFilePath)
    {
#if !WEBPLAYER
        try
        {
            File.Copy(inFilePath, outFilePath, true);
        }
        catch(DirectoryNotFoundException e2)
        {
            string dir = Path.GetDirectoryName(outFilePath);
            Directory.CreateDirectory(dir);
            return Copy(inFilePath, outFilePath);
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
            CommonUtil.Delete(outFilePath);
            return false;
        }
#endif
        return true;
    }

    public static byte[] fileToBytes(string filePath)
    {
        if(!File.Exists(filePath))
        {
            return null;
        }
        
        return File.ReadAllBytes(filePath);
    }

    public static bool stringToFile(string filePath, string str)
    {
#if !WEBPLAYER
        try
        {
            File.WriteAllText(filePath, str);
        }
        catch(DirectoryNotFoundException e2)
        {
            string dir = Path.GetDirectoryName(filePath);
            Directory.CreateDirectory(dir);
            return stringToFile(filePath, str);
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
            CommonUtil.Delete(filePath);
            return false;
        }
#endif
        return true;
    }

    public static string StreamToString(Stream srcStream)
    {
        StreamReader reader = new StreamReader(srcStream);
        return reader.ReadToEnd();
    }

    public static long GetFileSize(string filePath)
    {
        try
        {
            FileStream fileStream = File.OpenRead(filePath);
            long len = fileStream.Length;
            fileStream.Close();
            return len;
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
        }
        return 0;
    }
    
    public static void Delete(string filePath)
    {
        if(Directory.Exists(filePath))
        {
            Directory.Delete(filePath, true);
        }
        else if(File.Exists(filePath))
        {
            File.Delete(filePath);
        }
    }

    public static void ConvertFileToNoUTF8NoBom(string filePath)
    {
        FileStream fsr = File.OpenRead(filePath);
        byte[] bs = new byte[3];
        int len = fsr.Read(bs, 0, 3);

        if(len == 3 && bs[0] == 0xEF && bs[1] == 0xBB && bs[2] == 0xBF)
        {
            int fileSize = (int)GetFileSize(filePath);
            byte[] bs2 = new byte[fileSize - 3];
            fsr.Read(bs2, 0, fileSize - 3);
            fsr.Close();
            fsr = null;

            bytesToFile(filePath, bs2);

        }

        if(fsr != null)
        {
            fsr.Close();
            fsr = null;
        }
    }

    public static void CreateDir(string dir)
    {
        Directory.CreateDirectory(dir);
        //#if UNITY_IOS
        //      PlatformInvoke.Instance.AddSkipBackupDir(dir);
        //#endif
    }

    public static void CopyDirectory(string srcDir, string tgtDir)
    {
        DirectoryInfo source = new DirectoryInfo(srcDir);
        DirectoryInfo target = new DirectoryInfo(tgtDir);

        if (target.FullName.StartsWith(source.FullName, StringComparison.CurrentCultureIgnoreCase))
        {
            //throw new Exception("父目录不能拷贝到子目录！");
            return;
        }

        if (!source.Exists)
        {
            return;
        }

        if (!target.Exists)
        {
            target.Create();
        }

        FileInfo[] files = source.GetFiles();

        for (int i = 0; i < files.Length; i++)
        {
            File.Copy(files[i].FullName, target.FullName +  "/" + files[i].Name, true);
        }

        DirectoryInfo[] dirs = source.GetDirectories();

        for (int j = 0; j < dirs.Length; j++)
        {
            CopyDirectory(dirs[j].FullName, target.FullName + "/" + dirs[j].Name);
        }
    }
    
    public static bool Move(string srcPath, string destPath)
    {
        if (srcPath == destPath)
        {
            return true;
        }

        Delete(destPath);

#if !WEBPLAYER
        try
        {
            if(Directory.Exists(srcPath))
            {
                Directory.Move(srcPath, destPath);
            }
            else if(File.Exists(srcPath))
            {
                File.Move(srcPath, destPath);
            }
            else
            {
                return false;
            }
        }
        catch(DirectoryNotFoundException e2)
        {
            string dir = Path.GetDirectoryName(destPath);
            Directory.CreateDirectory(dir);
            return Move(srcPath, destPath);
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
            if(!Directory.Exists(srcPath) && Directory.Exists(destPath))
            {
                Directory.Move(destPath, srcPath);
            }
            else if(!File.Exists(srcPath) && File.Exists(destPath))
            {
                File.Move(destPath, srcPath);
            }
            return false;
        }
#endif
        return true;
    }

    public static string GetDirectoryName(string path)
    {
        path = System.IO.Path.GetDirectoryName(path);
        path = path.Replace("\\", "/");
        return path;
    }

    public static string toSizeString(float size, bool showGB = true)
    {
        string unit = null;
        float remain = 0;
        int de = 1024;
        if(size < de)
        {
            unit = "B";
        }

        if(unit == null)
        {
            remain = size % de;
            size /= de;
            if(size < de)
            {
                unit = "K";
            }
        }

        if (showGB)
        {
            if (unit == null)
            {
                remain = size % de;
                size /= de;
                if (size < de)
                {
                    unit = "M";
                }
            }

            if (unit == null)
            {
                remain = size % de;
                size /= de;
                if (size < de)
                {
                    unit = "G";
                }
            }
        }
        else
        {
            if (unit == null)
            {
                remain = size % de;
                size /= de;
                unit = "M";
            }
        }

        string format = null;
        if(remain < Mathf.Epsilon)
        {
            format = "{0:0}";
        }
        else
        {
            format = "{0:0.0}";
        }
        return string.Format(format, size)  + unit;

    }
    
    public static T ObjectFromJsonFile<T>(string filePath)
    {
        string str = fileToString(filePath);
        if (str == null)
        {
            return default(T);
        }

        try
        {
            T t = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
            return t;
        }
        catch(System.Exception e)
        {
            Debug.LogException(e);
        }
        return default(T);
    }

    public static void ObjectToJsonFile(object t, string filePath)
    {
        if (t == null)
        {
            return;
        }

        string str = Newtonsoft.Json.JsonConvert.SerializeObject(t, Newtonsoft.Json.Formatting.Indented);
        stringToFile(filePath, str);
    }

    public static string ObjectToJson(object t)
    {
        if (t == null)
        {
            return null;
        }

        string str = Newtonsoft.Json.JsonConvert.SerializeObject(t, Newtonsoft.Json.Formatting.Indented);
        return str;
    }

    public static T[] FindObjectsOfType<T>()
    {
        GameObject[] objs = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
        List<T> l = new List<T>();
        for (int i = 0; i < objs.Length; i++)
        {
            T[] ts = objs[i].GetComponentsInChildren<T>();
            l.AddRange(ts);
        }

        return l.ToArray();
    }


    public static bool CallMethod(string assemblyName, string className, string methodName, object[] parameters = null)
    {
        System.Reflection.Assembly gameAss = null;
        
        try
        {
            gameAss = System.AppDomain.CurrentDomain.GetAssemblies().First(assembly => assembly.GetName().Name == assemblyName);
        }
        catch(System.Exception e)
        {
            return false;
        }

        var appType = gameAss.GetType(className);
        if(appType == null)
        {
            return false;
        }

        var mainMethod = appType.GetMethod(methodName);
        if(mainMethod == null)
        {
            return false;
        }
        mainMethod.Invoke(null, parameters);
        return true;
    }

        public static (bool, object) CallMethodWithResult(string assemblyName, string className, string methodName, object[] parameters = null)
        {
            System.Reflection.Assembly gameAss = null;

            try
            {
                gameAss = System.AppDomain.CurrentDomain.GetAssemblies().First(assembly => assembly.GetName().Name == assemblyName);
            }
            catch (System.Exception e)
            {
                return (false, null);
            }

            var appType = gameAss.GetType(className);
            if (appType == null)
            {
                return (false, null);
            }

            var mainMethod = appType.GetMethod(methodName);
            if (mainMethod == null)
            {
                return (false, null);
            }
            var ret = mainMethod.Invoke(null, parameters);
            return (true, ret);
        }
    }
}